#ifndef PAGE_CACHE_H
#define PAGE_CACHE_H

#include <map>
#include <mutex>

namespace MemoryPool
{
    class PageCache
    {
    public:
        // constexpr 编译时计算还没有对象，需要static
        static constexpr size_t PAGE_SIZE = 4 * 1024; // 4KB页大小；CentralCache需要访问
        static PageCache &getInstance();

        // 分配指定页数的span
        void *allocSpan(const size_t needPageNum);
        // 回收指定页数的span
        // needPageNum表示后面需要合并的数量
        // TODO：实际上应该自动合并？可以用span->pageNum数量获取下一个地址
        // TODO：CentralCache未调用deallocSpan()
        // TODO: 合并后连续大内存到达阈值，可以考虑归还系统
        void deallocSpan(void *spanAddr, const size_t needPageNum);

    private:
        PageCache() = default;
        PageCache(const PageCache &) = delete;
        PageCache &operator=(const PageCache &) = delete;
        PageCache(PageCache &&) = delete;
        PageCache &operator=(PageCache &&) = delete;

        // 向系统申请内存
        void *allocSystemMem(const size_t needPageNum);

        struct Span
        {
            void *pageAddr; // 页起始地址
            size_t pageNum; // 页数
            Span *next;     // 链表指针
        };
        // 页数->空闲Span链表，用于分配
        std::map<size_t, Span *> freeSpans_;
        // 页地址->已用span，用于回收
        // 实际上，新创建+已使用未回收+使用过并回收的Span（放回freeSpans_，但没有从usedSpans_中删除）
        // 便于回收时查找相邻Span合并
        // 命名为 spanMap_ 更好
        std::map<void *, Span *> usedSpans_;

        std::mutex mtx_;
    };
} // namespace MemoryPool

#endif // PAGE_CACHE_H